#include "crc8.h"

void create_crc8_table16(CRC8_16 * p_crc8_16) {
    unsigned short index;
    unsigned char i;
    unsigned char poly;
    unsigned char tmp;

    if(p_crc8_16->crcRefIn) {
        poly = 0x00;
        for(i = 0; i < 8; i++) {
            poly = ((0x01 << i) & p_crc8_16->crcPoly) == 0 ? poly : (poly | (0x80 >> i));
        }
        for(index = 0; index < 16; index++) {
            tmp = (unsigned char)index;
            for(i = 4; i > 0; i--) {
                tmp = (tmp & 0x01) == 0x01 ? ((tmp >> 1) ^ poly) : (tmp >> 1);
            }
            p_crc8_16->crcTable[index] = tmp;
        }
    }
    else {
        poly = p_crc8_16->crcPoly;
        for(index = 0; index < 16; index++) {
            tmp = (unsigned char)index << 4;
            for(i = 4; i > 0; i--) {
                tmp = (tmp & 0x80) == 0x80 ? ((tmp << 1) ^ poly) : (tmp << 1);
            }
            p_crc8_16->crcTable[index] = tmp;
        }
    }
}

void create_crc8_table256(CRC8_256 * p_crc8_256) {
    unsigned short index;
    unsigned char i;
    unsigned char tmp;
    unsigned char poly;

    if(p_crc8_256->crcRefIn) {
        poly = 0x00;
        for(i = 0; i < 8; i++) {
            poly = ((0x01 << i) & p_crc8_256->crcPoly) == 0 ? poly : (poly | (0x80 >> i));
        }
        for(index = 0; index < 256; index++) {
            tmp = (unsigned char)index;
            for(i = 8; i > 0; i--) {
                tmp = (tmp & 0x01) == 0x01 ? ((tmp >> 1) ^ poly) : (tmp >> 1);
            }
            p_crc8_256->crcTable[index] = tmp;
        }
    }
    else {
        poly = p_crc8_256->crcPoly;
        for(index = 0; index < 256; index++) {
            tmp = (unsigned char)index;
            for(i = 8; i > 0; i--) {
                tmp = (tmp & 0x80) == 0x80 ? ((tmp << 1) ^ poly) : (tmp << 1);
            }
            p_crc8_256->crcTable[index] = tmp;
        }
    }
}

void prepare_crc8_with_table16(CRC8_16 * p_crc, unsigned char * crc8)
{
    unsigned char i;
    unsigned char tmp;
    if(p_crc->crcRefIn) {
        tmp = 0x00;
        for (i = 0; i < 8; i++) {
            tmp = ((0x01 << i) & p_crc->crcInit) == 0 ? tmp : (tmp | (0x80 >> i));
        }
    }
    else {
        tmp = p_crc->crcInit;
    }
    *crc8 = tmp;
}

void process_crc8_with_table16(CRC8_16 * p_crc, const unsigned char * character, unsigned char * crc8)
{
    unsigned char tmp;
    tmp = *crc8;
    if(p_crc->crcRefIn) {
        tmp = p_crc->crcTable[(*character ^ tmp) & 0x0f] ^ (tmp >> 4);
        tmp = p_crc->crcTable[((*character >> 4) ^ tmp) & 0x0f] ^ (tmp >> 4);
    }
    else {
        tmp = p_crc->crcTable[(*character >> 4) ^ (tmp >> 4)] ^ (tmp << 4);
        tmp = p_crc->crcTable[(*character & 0x0f) ^ (tmp >> 4)] ^ (tmp << 4);
    }
    *crc8 = tmp;
}

void complete_crc8_with_table16(CRC8_16 * p_crc, unsigned char * crc8)
{
    unsigned char i;
    unsigned char tmp;
    if((p_crc->crcRefIn !=0 && p_crc->crcRefOut != 0) || (p_crc->crcRefIn == 0 && p_crc->crcRefOut == 0)) {
        tmp = *crc8 ^ p_crc->crcXor;
    }
    else {
        tmp = 0x00;
        for(i = 0; i < 8; i++) {
            tmp = ((0x01 << i) & *crc8) == 0 ? tmp : (tmp | (0x80 >> i));
        }
        tmp = tmp ^ p_crc->crcXor;
    }
    *crc8 = tmp;
}

void prepare_crc8_with_table256(CRC8_256 * p_crc, unsigned char * crc8)
{
    unsigned char i;
    unsigned char tmp;
    if(p_crc->crcRefIn) {
        tmp = 0x00;
        for (i = 0; i < 8; i++) {
            tmp = ((0x01 << i) & p_crc->crcInit) == 0 ? tmp : (tmp | (0x80 >> i));
        }
    }
    else {
        tmp = p_crc->crcInit;
    }
    *crc8 = tmp;
}

void process_crc8_with_table256(CRC8_256 * p_crc, const unsigned char * character, unsigned char * crc8)
{
    *crc8 = p_crc->crcTable[*character ^ *crc8];
}

void complete_crc8_with_table256(CRC8_256 * p_crc, unsigned char * crc8)
{
    unsigned char i;
    unsigned char tmp;
    if((p_crc->crcRefIn !=0 && p_crc->crcRefOut != 0) || (p_crc->crcRefIn == 0 && p_crc->crcRefOut == 0)) {
        tmp = *crc8 ^ p_crc->crcXor;
    }
    else {
        tmp = 0x00;
        for(i = 0; i < 8; i++) {
            tmp = ((0x01 << i) & *crc8) == 0 ? tmp : (tmp | (0x80 >> i));
        }
        tmp = tmp ^ p_crc->crcXor;
    }
    *crc8 = tmp;
}

unsigned char generate_crc8(void * p_crc, unsigned int crc_table_size, const unsigned char * data, unsigned int length)
{
    unsigned int i;
    unsigned char tmp;
    unsigned char character;
    unsigned char crc_init;
    unsigned char crc_xor;
    unsigned char crc_refin;
    unsigned char crc_refout;
    unsigned char * crc_table;

    if(crc_table_size == 16) {
        crc_init = ((CRC8_16 *)p_crc)->crcInit;
        crc_xor = ((CRC8_16 *)p_crc)->crcXor;
        crc_refin = ((CRC8_16 *)p_crc)->crcRefIn;
        crc_refout = ((CRC8_16 *)p_crc)->crcRefOut;
        crc_table = ((CRC8_16 *)p_crc)->crcTable;
    }
    else if(crc_table_size == 256) {
        crc_init = ((CRC8_256 *)p_crc)->crcInit;
        crc_xor = ((CRC8_256 *)p_crc)->crcXor;
        crc_refin = ((CRC8_256 *)p_crc)->crcRefIn;
        crc_refout = ((CRC8_256 *)p_crc)->crcRefOut;
        crc_table = ((CRC8_256 *)p_crc)->crcTable;
    }
    else {
        return 0;
    }

    if(crc_refin) {
        tmp = 0x00;
        for (i = 0; i < 8; i++) {
            tmp = ((0x01 << i) & crc_init) == 0 ? tmp : (tmp | (0x80 >> i));
        }
    }
    else {
        tmp = crc_init;
    }

    if(crc_table_size == 16) {
        for(i = 0; i < length; i++) {
            character = data[i];
            if(crc_refin) {
                tmp = crc_table[(character ^ tmp) & 0x0f] ^ (tmp >> 4);
                tmp = crc_table[((character >> 4) ^ tmp) & 0x0f] ^ (tmp >> 4);
            }
            else {
                tmp = crc_table[(character >> 4) ^ (tmp >> 4)] ^ (tmp << 4);
                tmp = crc_table[(character & 0x0f) ^ (tmp >> 4)] ^ (tmp << 4);
            }
        }
    }
    else {
        for(i = 0; i < length; i++) {
            character = data[i];
            tmp = crc_table[character ^ tmp];
        }
    }

    if((crc_refin !=0 && crc_refout != 0) || (crc_refin == 0 && crc_refout == 0)) {
        tmp = tmp ^ crc_xor;
    }
    else {
        crc_init = tmp;
        tmp = 0x00;
        for(i = 0; i < 8; i++) {
            tmp = ((0x01 << i) & crc_init) == 0 ? tmp : (tmp | (0x80 >> i));
        }
        tmp = tmp ^ crc_xor;
    }

    return tmp;
}
